package abinly.harmony.permission.compiler;

import abinly.harmony.permission.*;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.util.*;

public class PermissionProcessor extends AbstractProcessor {

    private final HashSet<String> hashSet = new LinkedHashSet<>();

    private Filer mProcessorFiler;
    private Types mProcessorTypes;
    private Elements mProcessorElements;
    private Messager mProcessorMessager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        System.out.println("PermissionProcessor ====> init ");

        mProcessorFiler = processingEnv.getFiler();
        mProcessorTypes = processingEnv.getTypeUtils();
        mProcessorElements = processingEnv.getElementUtils();
        mProcessorMessager = processingEnv.getMessager();

        hashSet.add(CompilePermissions.class.getCanonicalName());
        hashSet.add(NeedsSelfPermission.class.getCanonicalName());
        hashSet.add(NeedsCallingPermission.class.getCanonicalName());
        hashSet.add(NeedsCallingOrSelfPermission.class.getCanonicalName());
        hashSet.add(OnPermissionBlocked.class.getCanonicalName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return hashSet;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(CompilePermissions.class);
        if (elements == null || elements.isEmpty()) {
            return false;
        }

        for (Element element : elements) {
            if (ElementKind.CLASS != element.getKind()) {
                String message = "Only classes can be annotated with CompilePermissions.";
                mProcessorMessager.printMessage(Diagnostic.Kind.ERROR, message, element);
                return false;
            }

            try {
                if (element instanceof TypeElement) {
                    CompilePermissionClassGenerator compilePermissionClassGenerator = new CompilePermissionClassGenerator((TypeElement) element);
                    compilePermissionClassGenerator.generateJavaCodeToFile(mProcessorElements, mProcessorFiler);
                }
            } catch (IOException e) {
                e.printStackTrace();
                mProcessorMessager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element);
                return false;
            }
        }

        return true;
    }
}
